#ifndef VMATH_H_
#define VMATH_H_

#include <math.h>

#ifdef __cplusplus
extern "C" {
#endif

/* vmVec3 */
typedef struct {
  float x, y, z;
} vmVec3;

/* vmVec4 */
typedef struct {
  float x, y, z, w;
} vmVec4;

/* vmMat3 */
typedef struct {
  vmVec3 c0, c1, c2;
} vmMat3;

/* vmMat4 */
typedef struct {
  vmVec4 c0, c1, c2, c3;
} vmMat4;

static inline vmVec3 *vmVec3Copy(vmVec3 *r, const vmVec3 *v);

static inline vmVec3 *vmVec3Set(vmVec3 *r, float x, float y, float z);
static inline vmVec3 *vmVec3SetFromScalar(vmVec3 *r, float s);

static inline vmVec3 *vmVec3Saturate(vmVec3 *r, const vmVec3 *v);

static inline vmVec3 *vmVec3Add(vmVec3 *r, const vmVec3 *v0, const vmVec3 *v1);
static inline vmVec3 *vmVec3Sub(vmVec3 *r, const vmVec3 *v0, const vmVec3 *v1);

/* Implementation */

static inline vmVec3 *vmVec3Copy(vmVec3 *r, const vmVec3 *v) {
  r->x = v->x; r->y = v->y; r->z = v->z;
  return r;
}

static inline vmVec3 *vmVec3Set(vmVec3 *r, float x, float y, float z) {
  r->x = x; r->y = y; r->z = z;
  return r;
}
static inline vmVec3 *vmVec3SetFromScalar(vmVec3 *r, float s) {
  r->x = r->y = r->z = s;
  return r;
}

static inline vmVec3 *vmVec3Saturate(vmVec3 *r, const vmVec3 *v) {
  vmVec3Copy(r, v);
  if (r->x < 0.0f) r->x = 0.0f; else if (r->x > 1.0f) r->x = 1.0f;
  if (r->y < 0.0f) r->y = 0.0f; else if (r->y > 1.0f) r->y = 1.0f;
  if (r->z < 0.0f) r->z = 0.0f; else if (r->z > 1.0f) r->z = 1.0f;
  return r;
}

static inline vmVec3 *vmVec3Add(vmVec3 *r, const vmVec3 *v0, const vmVec3 *v1) {
  r->x = v0->x + v1->x;
  r->y = v0->y + v1->y;
  r->z = v0->z + v1->z;
  return r;
}
static inline vmVec3 *vmVec3Sub(vmVec3 *r, const vmVec3 *v0, const vmVec3 *v1) {
  r->x = v0->x - v1->x;
  r->y = v0->y - v1->y;
  r->z = v0->z - v1->z;
  return r;
}

#ifdef __cplusplus
}
#endif

#endif
